home *** CD-ROM | disk | FTP | other *** search
/ Maclife 157 / MACLIFE157-2001-09.ISO.7z / MACLIFE157-2001-09.ISO / Linux / MacOS Tools / BootX 1.2.2 / Sources / src / bootx / BootX.c < prev    next >
C/C++ Source or Header  |  2001-07-23  |  52KB  |  2,066 lines

  1. /* BootX
  2.  *
  3.  * Written by Benjamin Herrenschmidt
  4.  *
  5.  * portions of this code from InfiniteOS boot loader by <...>, portions from
  6.  * quik by Paul Mackerras.
  7.  *
  8.  * GPL....
  9.  *
  10.  * This file contains the entry point and GUI of BootX. It contains code
  11.  * for both the application and INIT version of BootX, but not for miBoot.
  12.  * It does not contains all the code involved in loading the kernel and
  13.  * preparing the boot process itself. This code is shared with miBoot and
  14.  * is now located in boot.c
  15.  *
  16.  */
  17.  
  18. #include <Devices.h>
  19. #include <Files.h>
  20. #include <DriverServices.h>
  21. #include <PEFBinaryFormat.h>
  22. #include <ShutDown.h>
  23. #include <Dialogs.h>
  24. #include <Windows.h>
  25. #include <Menus.h>
  26. #include <LowMem.h>
  27. #include <DiskInit.h>
  28. #include <Processes.h>
  29. #include <TextUtils.h>
  30. #include <Resources.h>
  31. #include <AppleEvents.h>
  32. #include <AEDataModel.h>
  33. #include <Folders.h>
  34. #include <ToolUtils.h>
  35. #include <SCSI.h>
  36. #include <Gestalt.h>
  37. #include <Packages.h>
  38. #include <StandardFile.h>
  39.  
  40. #include <stdio.h>
  41. #include <string.h>
  42. #include <stdlib.h>
  43. #include <stdarg.h>
  44. #include "debug_text.h"
  45.  
  46. #ifndef macintosh
  47. #define macintosh
  48. #endif
  49.  
  50. #ifndef BOOTX_BUILD_INIT
  51. #define BOOTX_BUILD_INIT                (BOOTX_ENV == BOOTX_ENV_EXTENSION)
  52. #endif
  53.  
  54. /* This option reverts to old bootx behaviour: the kernel is entered
  55.    directly, without turnig OFF the MMU. */
  56. #ifndef NO_BOOTSTRAP
  57. #define NO_BOOTSTRAP                    0
  58. #endif
  59.  
  60. #include "BootX.h"
  61. #include "boot.h"
  62. #include "ErrorCodes.h"
  63.  
  64. #include "MoreFiles.h"
  65. #include "MoreFilesExtras.h"
  66. #include "IterateDirectory.h"
  67. #include "FullPath.h"
  68.  
  69. #ifndef TRUE
  70. #define TRUE    1
  71. #define FALSE    0
  72. #endif
  73.  
  74. #define DEBUG_ERR(err,msg)            display_error((err), msg, __FILE__, __LINE__)
  75.  
  76. #if BOOTX_BUILD_INIT
  77. /* Procinfo of entry point */
  78. ProcInfoType __procinfo = kPascalStackBased;
  79. #endif
  80.  
  81. /* Dialog items IDs */
  82. enum
  83. {
  84.     /* Main dialog */
  85.     button_boot_linux        = 2,
  86.     button_boot_macos        = 3,
  87.     field_kernel_args        = 5,
  88.     field_root_device        = 6,
  89.     button_set_default        = 7,
  90.     text_status_display        = 9,
  91.     check_video_of_only        = 11,
  92.     button_boot_mklinux        = 14,
  93.     menu_kernels            = 15,
  94.     button_options            = 16,
  95.     has_ramdisk_item        = 17,
  96.     root_label_1            = 12,
  97.     root_label_2            = 13,
  98.     ramd_label                = 18,
  99.     field_ramd_size            = 19,
  100.     
  101.     /* Options dialog */
  102.     opt_check_use_ram_disk        = 4,
  103.     opt_button_choose_ramdisk    = 7,
  104.     opt_text_ramdisk_path        = 6,
  105.     opt_check_set_l2cr            = 3,
  106.     opt_check_force_video        = 8,
  107.     opt_check_force_scsi_on        = 5,
  108.     opt_button_ok                = 1,
  109.     opt_button_cancel            = 2
  110. };
  111.  
  112. /* Resources */
  113. enum
  114. {
  115.     string_kernel_names        = 128,
  116.     string_ramdisk_names    = 129,
  117.     string_kernel_args        = 130,
  118.     string_prefs_file_names    = 131,
  119.     string_boot_delay        = 132,
  120.     string_mkboot_names        = 133,
  121.     string_mkboot_patch        = 134,
  122.     string_kernel_folder    = 135,
  123.     
  124.     string_mkboot_patched    = 257,
  125.     
  126.     text_mkboot_fake_prefs    = 128,
  127.  
  128.     dialog_main                = 131,
  129.     dialog_options            = 132,
  130.     alert_error                = 130,
  131.     
  132.     menu_kernel_list        = 1000,
  133.     
  134.     icons_ramdisk            = 258,
  135.     icons_gzipped            = 260,
  136.     icons_normal_kernel        = 259
  137. };
  138.  
  139. /* Boot choice */
  140. enum
  141. {
  142.     boot_macos    = 0,
  143.     boot_linux,
  144.     boot_mklinux,
  145.     
  146.     boot_choice_count = 3
  147. };
  148.  
  149. static short g_boot_choices[boot_choice_count][2] = 
  150. {
  151.     button_boot_macos    , 1,
  152.     button_boot_linux    , 0,
  153.     button_boot_mklinux    , 0
  154. };
  155.  
  156.  
  157. /* Struct used for mount event queue */
  158. typedef struct saved_mount
  159. {
  160.     QElem    link;
  161.     UInt32    message;
  162.     
  163. } saved_mount_t;
  164.  
  165. /* An item in the kernel list. Note that an empty name
  166.    means a separator item */
  167. typedef struct kernel_item
  168. {
  169.     boot_file_t            file;
  170.     boot_kernel_desc_t    kdesc;
  171.     boot_ramdisk_desc_t    rdesc;
  172.     Boolean                has_rd;
  173.     short                menu_item;
  174.     
  175. } kernel_item_t;
  176.  
  177. #define MAX_KERNEL_ITEMS    32
  178.  
  179. /* Preferences */
  180.  
  181. #define BOOTX_PREFS_VERSION                5
  182. #define BOOTX_PREFS_COMPATIBLE_VERSION    1
  183.  
  184. #pragma options align=power
  185. typedef struct bootx_prefs
  186. {
  187.     /* Version of this structure */
  188.     unsigned long    version;
  189.     /* backward compatible down to version: */
  190.     unsigned long    compatible_version;
  191.  
  192.     unsigned char    boot_choice;    // uchar for compatibility
  193.     Boolean            use_ramdisk;
  194.     Boolean            video_of_only;
  195.     Boolean            use_l2cr_settings;
  196.     Boolean            force_video_setup;
  197.     Boolean            force_scsi_on;
  198.     Boolean            unused_boolean[2];
  199.     Str255            command_line;
  200.     Str32            root_device;
  201.     Str63            kernel_name;
  202.     char            ramdisk_path[1024];
  203.     UInt32            ramdisk_size;
  204. } bootx_prefs, **bootx_prefs_handle;
  205. #pragma options align=reset
  206.  
  207. /* Generic tools */
  208. inline void
  209. pstrcpy(Str255 dst, ConstStr255Param src)
  210. {
  211.     memcpy(dst, src, src[0] + 1);
  212. }
  213.  
  214. inline void
  215. pstrncpy(Str255 dst, ConstStr255Param src, unsigned long max_size)
  216. {
  217.     unsigned char l = (src[0] > max_size) ?
  218.     max_size : src[0]; memcpy(dst, src, l+1);
  219.     dst[0] = l;
  220. }
  221.  
  222. inline void
  223. pstrcat(Str255 dst, ConstStr255Param append)
  224. {
  225.     int size = append[0];
  226.     
  227.     if ((dst[0] + size) > 255)
  228.         size = 255 - dst[0];
  229.         
  230.     memcpy(&dst[dst[0]+1], &append[1], size);
  231.     
  232.     dst[0] += size;
  233. }
  234.  
  235. /* --- Prototypes -------------------------------------- */
  236.  
  237. typedef void (*iterate_device_proc)(RegEntryIDPtr entryID);
  238.  
  239. pascal void            main(void);
  240.  
  241. static void            init_macos_toolbox(void);
  242. static Boolean        create_dialog(void);
  243. static void            dispose_dialog(void);
  244. static Boolean        locate_ramdisk(void);
  245. static void            setup_default_buttons(void);
  246. static void            display_error(OSErr err, int msg, char *file, int line);
  247. static void            fill_boot_options(    boot_kernel_desc_t    **out_kernel_infos,
  248.                                         boot_ramdisk_desc_t    **out_ramdisk_infos,
  249.                                         boot_params_t        *out_params);
  250. static OSErr        locate_file(short namesResourceID, OSType defaultFolder, FSSpecPtr outSpec);
  251. static void            load_prefs(void);
  252. static void            save_prefs(void);
  253. static void            do_boot_mklinux(void);
  254. static Boolean        locate_mklinux(void);
  255. static Boolean        add_kernel_file(FSSpec *in_spec);
  256. static void            lookup_kernels(void);
  257. static void            do_main_dialog(void);
  258. static void            do_options_dialog(void);
  259. static pascal void    kernel_iterate_filter_proc(    const CInfoPBRec*    const cpbPtr,
  260.                                                 Boolean                *quitFlag,
  261.                                                 void*                yourDataPtr);
  262. static void            build_kernels_menu(void);
  263. static void            setup_debug_context(Boolean debug_visible);
  264. static void            check_opt_keys(void);
  265. static void            debug_checkpoint(void);
  266. static void            show_context(void);
  267. static pascal void    ramdisk_icon_item_proc(WindowPtr theWindow, DialogItemIndex itemNo);
  268. static void            kernel_selection_changed();
  269. static Boolean        choose_ramdisk_file(boot_file_t* file, boot_ramdisk_desc_t* desc);
  270.  
  271.  
  272. #if BOOTX_BUILD_INIT
  273. static void            save_mount_event(EventRecord *event);
  274. static void            resend_mount_events(void);
  275. #endif
  276.  
  277. // CFM stuffs
  278. pascal OSErr        FragmentInitialize(const CFragInitBlockPtr initInfo);
  279. pascal void            FragmentTerminate(void);
  280. pascal OSErr        __initialize(const CFragInitBlockPtr initInfo);
  281. pascal void            __terminate(void);
  282.  
  283.  
  284. /* --- Globals ----------------------------------------- */
  285.  
  286. extern int device_tree_skip_macos;
  287. extern int device_tree_max_prop_length;
  288.  
  289. dt_context*    dct;
  290.  
  291. static dt_context                            g_dct;
  292. static Boolean                                g_use_ramdisk;
  293. static void*                                g_ramdisk;
  294. static boot_ramdisk_desc_t                    g_std_ramdisk;
  295. static boot_file_t                            g_std_ramdisk_file;
  296. static Boolean                                g_video_of_only;
  297. static ControlHandle                        g_video_of_only_cntl;
  298. static DialogPtr                            g_dialog;
  299. static THz                                    g_my_zone;
  300. static FSSpec                                g_mkboot_spec;
  301. static Boolean                                g_have_ramdisk;
  302. static int                                    g_current_choice;
  303. static UInt32                                g_entry_ticks;
  304. static UInt32                                g_autoboot_delay;
  305. static Handle                                g_status_item;
  306. static QHdr                                    g_mount_queue;
  307. static Boolean                                g_vm_present;
  308. static Boolean                                g_L2CR_pref;
  309. static Boolean                                g_L2CR_set;
  310. static Boolean                                g_L2CR_available;
  311. static UInt32                                g_L2CR_value;
  312. /*static*/ Boolean                            g_arch_PCI;                /* Needed by do_boot to avoid device tree copy on Nubus */
  313. static ControlHandle                        g_kernel_menu = NULL;
  314. static kernel_item_t                        g_kernel_items[MAX_KERNEL_ITEMS];
  315. static UInt32                                g_kernel_items_count = 0;
  316. static Boolean                                g_debug_visible = 0;
  317. static Boolean                                g_current_kernel_has_rd = false;
  318. static Boolean                                g_force_video_setup = false;
  319. static Boolean                                g_force_scsi_on = false;
  320. static Handle                                ramd_size_field;
  321. static Boolean                                g_reset_ata = true;
  322.  
  323. #if !BOOTX_BUILD_INIT
  324. static FSSpec                                g_application_spec;
  325. #endif
  326.  
  327. static RGBColor                                g_back_color = {0xEEEE, 0xEEEE, 0xEEEE};
  328.  
  329. /* --- Implementation ---------------------------------- */
  330.  
  331. /* Pre-initialize */
  332. pascal OSErr
  333. FragmentInitialize(const CFragInitBlockPtr /*initInfo*/)
  334. {
  335. // -- Not needed if we don't use C++
  336. //    OSErr    err = __initialize(initInfo);
  337. //    if (err != noErr)
  338. //        return err;
  339. //
  340. //    g_my_connection_ID = (CFragConnectionID)initInfo->connectionID;
  341. //
  342. //
  343. //    SetDriverClosureMemory(initInfo->closureID, true);
  344.  
  345.     return noErr;
  346. }
  347.  
  348. pascal void
  349. FragmentTerminate(void)
  350. {
  351. // -- Not needed if we don't use C++
  352. //    __terminate();
  353.  
  354. //    DebugStr("¥pFrag term");
  355. }
  356.  
  357.  
  358. /* Initialize MacOS managers */
  359. void
  360. init_macos_toolbox(void)
  361. {
  362. #if !BOOTX_BUILD_INIT
  363.     OSErr                err;
  364.     ProcessInfoRec        infos;
  365.     ProcessSerialNumber    me;
  366.     Str255                my_name;
  367. #endif
  368.  
  369.     InitGraf(&qd.thePort);
  370.     InitFonts();
  371.     InitWindows();
  372. #if BOOTX_BUILD_INIT
  373.     InitMenus();
  374. #endif    
  375.     TEInit();
  376.     InitDialogs(nil);
  377. #if BOOTX_BUILD_INIT
  378.     InitAllPacks();
  379. #endif    
  380.     InitCursor();
  381. #if BOOTX_BUILD_INIT
  382.     LMSetDeskHook(NULL);
  383.     LMSetDragHook(NULL);
  384.     LMSetGhostWindow(NULL);
  385.     TextFont(0);
  386.     TextSize(12);
  387.     DrawMenuBar();
  388. #endif
  389.     
  390. #if BOOTX_BUILD_INIT
  391.     MoreMasters();
  392. #else
  393.     MaxApplZone();
  394.     MoreMasters();
  395.     MoreMasters();
  396.     MoreMasters();
  397.     MoreMasters();
  398.  
  399.     FlushEvents(everyEvent, 0);
  400.  
  401.     err = GetCurrentProcess(&me);
  402.     if (err != noErr) {
  403.         DEBUG_ERR(err, error_get_current_process);
  404.         ExitToShell();
  405.     }
  406.  
  407.     memset(&infos, 0, sizeof(ProcessInfoRec));
  408.     infos.processInfoLength        = sizeof(ProcessInfoRec);
  409.     infos.processName            = my_name;
  410.     infos.processAppSpec        = &g_application_spec;
  411.     err = GetProcessInformation(&me, &infos);
  412.     if (err != noErr)
  413.     {
  414.         DEBUG_ERR(err, error_get_process_infos);
  415.         ExitToShell();
  416.     }    
  417. #endif
  418. }
  419.  
  420. static RoutineDescriptor    ramdisk_icon_item_desc =
  421.     BUILD_ROUTINE_DESCRIPTOR(uppUserItemProcInfo, ramdisk_icon_item_proc);
  422.  
  423. static pascal void ramdisk_icon_item_proc(WindowPtr theWindow, DialogItemIndex itemNo)
  424. {
  425.     Handle            hdl;
  426.     Rect            rect;
  427.     DialogItemType    type;
  428.     
  429.     SetPort(theWindow);
  430.     GetDialogItem(theWindow, itemNo, &type, &hdl, &rect);
  431.     PlotIconID(&rect, kAlignNone, kTransformNone, icons_ramdisk);
  432. }
  433.     
  434. /* Create the dialog, setup initial values, and gather infos about some
  435.  * of the items for later use.
  436.  */
  437. Boolean
  438. create_dialog()
  439. {
  440.     DialogPeek                dp;
  441.     short                    itemType;
  442.     Rect                    itemBox;
  443.     Handle                    itemHandle;
  444.     FontInfo                theFontInfo;
  445.     Str32                    tempStr;
  446.     
  447.     g_dialog = GetNewDialog(dialog_main, NULL, (WindowPtr)-1);
  448.     if (!g_dialog)
  449.     {
  450.         DEBUG_ERR(0, error_create_dialog);
  451.         return false;
  452.     }
  453.     SetPort(g_dialog);
  454.     
  455.     dp = (DialogPeek)g_dialog;
  456.     TextFont((**(dp->textH)).txFont = 3);
  457.     TextSize((**(dp->textH)).txSize = 9);
  458.     TextFace((**(dp->textH)).txFace = 0);
  459.     GetFontInfo(&theFontInfo);
  460.     (**(dp->textH)).lineHeight = theFontInfo.ascent + theFontInfo.descent + theFontInfo.leading;
  461.     (**(dp->textH)).fontAscent = theFontInfo.ascent;
  462.  
  463.     GetDialogItem(g_dialog, text_status_display, &itemType, &g_status_item, &itemBox) ;
  464.  
  465.     GetDialogItem(g_dialog, button_boot_linux, &itemType, &itemHandle, &itemBox) ;
  466.     if (!g_boot_choices[boot_linux][1])
  467.         HiliteControl((ControlHandle)itemHandle, 255);
  468.     GetDialogItem(g_dialog, button_boot_mklinux, &itemType, &itemHandle, &itemBox) ;
  469. #if BOOTX_BUILD_INIT
  470.     if (!g_boot_choices[boot_mklinux][1])
  471.         HiliteControl((ControlHandle)itemHandle, 255);
  472. #else
  473.     HideDialogItem(g_dialog, button_boot_mklinux);
  474. #endif
  475.     GetDialogItem(g_dialog, check_video_of_only, &itemType, (Handle *)&g_video_of_only_cntl, &itemBox) ;
  476.  
  477.     GetDialogItem(g_dialog, has_ramdisk_item, &itemType, &itemHandle, &itemBox) ;
  478.     SetDialogItem(g_dialog, has_ramdisk_item, itemType, (Handle)&ramdisk_icon_item_desc, &itemBox) ;
  479.     HideDialogItem(g_dialog, has_ramdisk_item);
  480.  
  481.     GetDialogItem(g_dialog, field_ramd_size, &itemType, &ramd_size_field, &itemBox) ;
  482.     NumToString(8192, tempStr);
  483.     SetDialogItemText(ramd_size_field, tempStr);
  484.     
  485.     SetDialogTracksCursor(g_dialog, true);
  486.     
  487.     RGBBackColor(&g_back_color);
  488.     
  489.     GetDialogItem(g_dialog, menu_kernels, &itemType, (Handle *)&g_kernel_menu, &itemBox);
  490.     
  491.     return true;
  492. }
  493.  
  494. void
  495. fill_boot_options(            boot_kernel_desc_t    **out_kernel_infos,
  496.                             boot_ramdisk_desc_t    **out_ramdisk_infos,
  497.                             boot_params_t        *out_params)
  498. {
  499.     short                    itemType;
  500.     Rect                    itemBox;
  501.     Handle                    itemHandle;
  502.     static Str255            tempStr;
  503.     static Str255            args;
  504.     int                        i, choice;
  505.     boot_kernel_desc_t*        ki;
  506.     boot_ramdisk_desc_t*    ri;
  507.     
  508.     tempStr[0] = args[0] = 0;
  509.  
  510.     out_params->close_video        = true;
  511.     out_params->no_relocation    = false;
  512.     out_params->setup_video     = g_force_video_setup;
  513.     out_params->force_scsi        = g_force_scsi_on;
  514.     out_params->override_l2cr    = g_L2CR_set;
  515.     out_params->l2cr_value        = g_L2CR_value;
  516.     out_params->reset_ata        = g_reset_ata;
  517.  
  518.     if (!g_use_ramdisk && !g_current_kernel_has_rd) {
  519.         GetDialogItem(g_dialog, field_root_device, &itemType, &itemHandle, &itemBox);
  520.         if (itemHandle)
  521.             GetDialogItemText(itemHandle, tempStr);
  522.         if (tempStr[0]) {
  523.             pstrcpy(args, "¥proot=/dev/");
  524.             pstrcat(args, tempStr);
  525.         }
  526.     } else {
  527.         long size;
  528.         GetDialogItemText(ramd_size_field, tempStr);
  529.         StringToNum(tempStr, &size);
  530.         if (size) {
  531.             NumToString(size, tempStr);
  532.             pstrcpy(args, "¥pramdisk_size=");
  533.             pstrcat(args, tempStr);
  534.         }
  535.     }
  536.  
  537.     tempStr[0] = 0;
  538.     GetDialogItem(g_dialog, field_kernel_args, &itemType, &itemHandle, &itemBox);
  539.     if (itemHandle)
  540.         GetDialogItemText(itemHandle, tempStr);
  541.     if (tempStr[0]) {
  542.         if (args[0])
  543.             pstrcat(args, "¥p ");
  544.         pstrcat(args, tempStr);
  545.     }
  546.  
  547.     // Eventually update kernel args for ofonly mode
  548.     if (g_video_of_only) {
  549.         if (args[0])
  550.             pstrcat(args, "¥p ");
  551.         pstrcat(args, "¥pvideo=ofonly");
  552.     }
  553.  
  554.     // Get selected kernel
  555.     choice = 0;
  556.     for (i=0; i<g_kernel_items_count; i++)
  557.         if (g_kernel_items[i].menu_item == GetControlValue(g_kernel_menu))
  558.             choice = i;
  559.  
  560.     pstrcpy((StringPtr)out_params->args, args);
  561.     p2cstr((StringPtr)out_params->args);
  562.     
  563.     *out_kernel_infos = ki = &g_kernel_items[choice].kdesc;
  564.     ri = NULL;
  565.     if (g_kernel_items[choice].has_rd)
  566.         ri = &g_kernel_items[choice].rdesc;
  567.     else if (g_use_ramdisk) {
  568.         ri = &g_std_ramdisk;
  569.     }    
  570.     *out_ramdisk_infos = ri;
  571.     
  572. }
  573.  
  574. /* I'll let you guess what this function does ;-)
  575.  */
  576. void
  577. dispose_dialog()
  578. {
  579.     Boolean    hasEvent;
  580.     
  581.     /* Flush any pending update event */
  582.     do {
  583.         EventRecord     event;
  584.         
  585.         hasEvent = WaitNextEvent(everyEvent & (~diskMask), &event, 1, NULL);
  586.         if (hasEvent && (event.what == updateEvt)) {
  587.             SetPort((WindowPtr)event.message);
  588.             BeginUpdate((WindowPtr)event.message);
  589.             EndUpdate((WindowPtr)event.message);
  590.         }
  591.     } while(hasEvent);
  592.     
  593.     /* Get rid of the dialog */
  594.     DisposeDialog(g_dialog);
  595.     g_dialog = NULL;
  596. }
  597.  
  598. void
  599. setup_default_buttons(void)
  600. {
  601.     Rect        r_erase, r_fill;
  602.     RgnHandle    erase_rgn, rgn1, rgn2;
  603.     PenState    state;
  604.     short        button, i;
  605.     short        itemType;
  606.     Handle        itemHandle;
  607.     
  608.     SetPort(g_dialog);
  609.     
  610.     button = g_boot_choices[g_current_choice][0];
  611.     SetDialogDefaultItem(g_dialog, button);
  612.     SetDialogCancelItem(g_dialog, button_boot_macos);
  613.  
  614.     erase_rgn = NewRgn();
  615.     rgn1 = NewRgn();
  616.     rgn2 = NewRgn();
  617.     
  618.     for (i=0; i<boot_choice_count; i++)
  619.         if (i == g_current_choice)
  620.             GetDialogItem(g_dialog, g_boot_choices[i][0], &itemType, &itemHandle, &r_fill) ;
  621.         else
  622.         {
  623.             GetDialogItem(g_dialog, g_boot_choices[i][0], &itemType, &itemHandle, &r_erase);
  624.             RectRgn(rgn1, &r_erase);
  625.             InsetRect(&r_erase, -4, -4);
  626.             RectRgn(rgn2, &r_erase);
  627.             DiffRgn(rgn2, rgn1, rgn1);
  628.             UnionRgn(rgn1, erase_rgn, erase_rgn);
  629.         }
  630.  
  631.     /* We still do the erasing & drawing of the default outline
  632.        since some versions of the default filter proc will not handle
  633.        correctly the dynamic changing. Appearance Manager patches
  634.        FrameRoundRect so this won't harm. Under MacOS 8.1, the Appearance
  635.        won't be available so early during boot. Under 8.5, things seems to be
  636.        different and you'll get the AM look at startup.
  637.      */
  638.     GetPenState(&state);
  639.     PenNormal();
  640.     PenSize(3,3);
  641.     InsetRect(&r_fill, -4, -4);
  642.     EraseRgn(erase_rgn);    
  643.     FrameRoundRect(&r_fill, 16, 16);
  644.     SetPenState(&state);
  645.     
  646.     DisposeRgn(rgn1);
  647.     DisposeRgn(rgn2);
  648.     DisposeRgn(erase_rgn);
  649. }
  650.  
  651. OSErr
  652. locate_file(short namesResourceID, OSType defaultFolder, FSSpecPtr outSpec)
  653. {
  654.     int                i;
  655.     OSErr            err;
  656.     short            defaultVRefNum;
  657.     long            defaultParID;
  658.     static Str255    fileName;
  659. #if !BOOTX_BUILD_INIT
  660.     Boolean            tryApp;
  661. #endif
  662.  
  663.     // Build kernel FSSpec
  664.     err = FindFolder(    kOnSystemDisk,
  665.                         defaultFolder,
  666.                         false,
  667.                         &defaultVRefNum,
  668.                         &defaultParID);
  669.     if (err != noErr)
  670.         return err;
  671.  
  672.     i=1;
  673. #if !BOOTX_BUILD_INIT
  674.     tryApp = true;
  675. #endif    
  676.  
  677.     do
  678.     {
  679.         GetIndString(fileName, namesResourceID, i);
  680.         if (fileName[0] == 0)
  681.         {
  682. #if !BOOTX_BUILD_INIT
  683.             if (tryApp)
  684.             {
  685.                 tryApp = false;
  686.                 i = 1;
  687.                 continue;
  688.             }
  689. #endif            
  690.             return fnfErr;
  691.         }
  692.         
  693. #if BOOTX_BUILD_INIT
  694.         err = FSMakeFSSpec(    defaultVRefNum, defaultParID, fileName, outSpec);
  695. #else
  696.         err = FSMakeFSSpec(    tryApp ? g_application_spec.vRefNum : defaultVRefNum,
  697.                             tryApp ? g_application_spec.parID : defaultParID,
  698.                             fileName,
  699.                             outSpec);
  700. #endif
  701.         if (err == noErr)
  702.         {
  703.             Boolean wasFolder;
  704.             Boolean wasAlias;
  705.             
  706.             /* Resolve it in case it was an alias - should do it silently however !*/
  707.             ResolveAliasFile(    outSpec,
  708.                                 true,
  709.                                 &wasFolder,
  710.                                 &wasAlias);
  711.             break;
  712.         }
  713.         
  714.         i++;
  715.     } while(true);
  716.     
  717.     return err;
  718. }
  719.  
  720. /* Locate the kernel and the ram disk (optional) files on disk.
  721.  * This function uses a looks for them first next to the BootX application,
  722.  * then in the system folder's root.
  723.  * For each file, all possible names are tested. The names are stored inside
  724.  * BootX resources STR#, ID 128 for kernel names, ID 129 for ramdisk names
  725.  */
  726. Boolean
  727. locate_ramdisk(void)
  728. {
  729.     OSErr            err;
  730.     FSSpec            spec;
  731.     
  732.     // Lookup ram disk
  733.     g_have_ramdisk = false;
  734.     err = locate_file(string_ramdisk_names, kSystemFolderType, &spec);
  735.     if (err != noErr)
  736.         err = locate_file(string_ramdisk_names, kExtensionFolderType, &spec);
  737.     if (err == noErr) {
  738.         g_std_ramdisk_file.spec = spec;
  739.         g_std_ramdisk_file.rn    = -1;
  740.         g_std_ramdisk_file.size    = 0;
  741.         g_std_ramdisk_file.name    = g_std_ramdisk_file.spec.name;
  742.         
  743.         g_have_ramdisk = check_ramdisk_file( &g_std_ramdisk_file,
  744.                                              &g_std_ramdisk);
  745.     }
  746.  
  747.     return true;
  748. }
  749.  
  750. #if BOOTX_BUILD_INIT
  751.  
  752. /* Save bad mount events in our special queue. We repost them later so they can
  753.  * eventually be handled by an external file system that gets loaded after
  754.  * us (like MountX).
  755.  */
  756. void
  757. save_mount_event(EventRecord *event)
  758. {
  759.     saved_mount_t*    stub;
  760.     
  761. static s_save_count = 0;    
  762.     
  763.     dt_printf(dct, "saving mount event, msg: 0x%x, error: 0x%x¥n",
  764.             (int)LoWord(event->message), HiWord(event->message));
  765.  
  766.     if ((++s_save_count) > 128) {
  767.         DEBUG_ERR(-666, error_too_many_mounts);
  768.         return;
  769.     }
  770.     stub = (saved_mount_t*)NewPtr(sizeof(saved_mount_t));
  771.     if (stub == NULL)
  772.         stub = (saved_mount_t*)NewPtrSys(sizeof(saved_mount_t));
  773.     if (stub == NULL) {
  774.         DEBUG_ERR(MemError(), error_alloc_event_stub);
  775.         return;
  776.     }
  777.     
  778.     stub->message = event->message;
  779.     
  780.     Enqueue((QElemPtr)stub, &g_mount_queue);
  781. }
  782.  
  783. /* Repost events gathered previously */
  784. void
  785. resend_mount_events(void)
  786. {
  787.     saved_mount_t*    stub;
  788.     while(NULL != (stub = (saved_mount_t *)g_mount_queue.qHead))
  789.     {
  790.         if (Dequeue((QElemPtr)stub, &g_mount_queue) == noErr) {
  791.             OSErr    eventResult = HiWord(stub->message);
  792.             short    driveNumber = LoWord(stub->message);
  793.             
  794.             dt_printf(dct,"posting event, drive: 0x%x, error was: 0x%x¥n", (int)driveNumber, eventResult);
  795.             SetZone(SystemZone());
  796.             PostEvent(diskEvt, driveNumber);
  797.             SetZone(g_my_zone);
  798.             DisposePtr((Ptr)stub);
  799.         }
  800.     }
  801. }
  802.  
  803. #endif
  804.  
  805. Boolean
  806. add_kernel_file(FSSpec *in_spec)
  807. {
  808.     UInt32            index = g_kernel_items_count;
  809.     kernel_item_t    *item = &g_kernel_items[index];
  810.     
  811.     if (index >= MAX_KERNEL_ITEMS)
  812.         false;
  813.     
  814.     memset(item, 0, sizeof(kernel_item_t));
  815.     item->file.spec     = *in_spec;
  816.     item->file.name        = item->file.spec.name;
  817.     item->file.rn        = -1;
  818.     item->file.size        = 0;
  819.     item->kdesc.file    = &item->file;
  820.     item->rdesc.file    = &item->file;
  821.     item->has_rd        = false;
  822.     item->menu_item        = -1;
  823.     
  824.     if (check_kernel_file(&item->file, &item->kdesc, &item->rdesc, &item->has_rd)) {
  825.         g_kernel_items_count++;
  826.         return true;
  827.     }
  828.     return false;
  829. }
  830.  
  831. /* This function looks up possible linux kernel files and fills the
  832.    kernel menu */
  833. void
  834. lookup_kernels(void)
  835. {
  836.     FSSpec    spec, folder_spec, previous;
  837.     Str255    folder_name;
  838.     Boolean    isDir, has_previous;
  839.     long    folder_id, defaultParID;
  840.     short    defaultVRefNum;
  841.     OSErr    err;
  842.     
  843.     // Lookup kernel old way in system folder/application
  844.     has_previous = false;
  845.     err = locate_file(string_kernel_names, kSystemFolderType, &spec);
  846.     if (err == noErr) {
  847.         if (add_kernel_file(&spec)) {
  848.             has_previous = true;
  849.             previous = spec;
  850.         }
  851.     }
  852.     
  853.     // Lookup kernel old way in extensions folder/application
  854.     err = locate_file(string_kernel_names, kExtensionFolderType, &spec);
  855.     if (err == noErr) {
  856.         if (!(has_previous && (spec.vRefNum == previous.vRefNum)
  857.           && (spec.parID == previous.parID)
  858.           && EqualString(spec.name, previous.name, false, false)))
  859.             add_kernel_file(&spec);
  860.     }
  861.     
  862.     GetIndString(folder_name, string_kernel_folder, 1);
  863.     
  864.     // Now check for a "Linux Kernels" folder next to BootX (app only)
  865. #if !BOOTX_BUILD_INIT
  866.     err = FSMakeFSSpec(    g_application_spec.vRefNum,
  867.                         g_application_spec.parID,
  868.                         folder_name, &folder_spec);
  869.     if (err == noErr) {
  870.         Boolean wasFolder;
  871.         Boolean wasAlias;
  872.             
  873.         /* Resolve it in case it was an alias - should do it silently however !*/
  874.         ResolveAliasFile(&folder_spec, true, &wasFolder, &wasAlias);
  875.         err = FSpGetDirectoryID(&folder_spec, &folder_id, &isDir);
  876.         if ((err == noErr) && isDir) {
  877.             err = FSpIterateDirectory(    &folder_spec,
  878.                                         1,
  879.                                         kernel_iterate_filter_proc,
  880.                                         NULL);
  881.         }
  882.     }
  883. #endif
  884.  
  885.     // Now check for a "Linux Kernels" folder in the system folder
  886.     // Build kernel FSSpec
  887.     err = FindFolder(    kOnSystemDisk,
  888.                         kSystemFolderType,
  889.                         false,
  890.                         &defaultVRefNum,
  891.                         &defaultParID);
  892.     if (err == noErr) {
  893.         err = FSMakeFSSpec(    defaultVRefNum,
  894.                             defaultParID,
  895.                             folder_name, &folder_spec);
  896.         if (err == noErr) {
  897.             Boolean wasFolder;
  898.             Boolean wasAlias;
  899.             
  900.             /* Resolve it in case it was an alias - should do it silently however !*/
  901.             ResolveAliasFile(&folder_spec, true, &wasFolder, &wasAlias);
  902.             err = FSpGetDirectoryID(&folder_spec, &folder_id, &isDir);
  903.             if ((err == noErr) && isDir) {
  904.                 err = FSpIterateDirectory(    &folder_spec,
  905.                                             1,
  906.                                             kernel_iterate_filter_proc,
  907.                                             NULL);
  908.             }
  909.         }
  910.     }
  911. }  
  912.  
  913. pascal void
  914. kernel_iterate_filter_proc(    const CInfoPBRec*    const cpbPtr,
  915.                             Boolean                *quitFlag,
  916.                             void*                yourDataPtr)
  917. {
  918. #pragma unused (quitFlag,yourDataPtr)
  919.     FSSpec spec;
  920.     
  921.     pstrcpy(spec.name, cpbPtr->hFileInfo.ioNamePtr);
  922.     spec.parID = cpbPtr->hFileInfo.ioFlParID;
  923.     spec.vRefNum = cpbPtr->hFileInfo.ioVRefNum;
  924.     add_kernel_file(&spec);
  925. }
  926.  
  927. void
  928. build_kernels_menu(void)
  929. {
  930.     int                        item, i;
  931.     short                    lastVol;
  932.     long                    lastDirID;
  933.     MenuHandle                menu;
  934.     PopupPrivateDataHandle    dataH;
  935.         
  936.     lastDirID    = 0;
  937.     lastVol        = 0;
  938.     item        = 1;
  939.     
  940.     dataH =    (PopupPrivateDataHandle) (**g_kernel_menu).contrlData;
  941.     menu = NULL;
  942.     if (dataH != NULL)
  943.         menu = (**dataH).mHandle;
  944.     if (!menu)
  945.         return;
  946.  
  947.     while(CountMenuItems(menu))
  948.         DeleteMenuItem(menu, 1);
  949.     for (i=0; i<g_kernel_items_count; i++) {
  950.         if ((item > 1) && ((g_kernel_items[i].file.spec.vRefNum != lastVol)
  951.             || (g_kernel_items[i].file.spec.parID != lastDirID))) {
  952.             AppendMenu(menu, "¥p(-");
  953.             item++;
  954.         }
  955.         AppendMenu(menu, "¥p ");
  956.         SetMenuItemText(menu, item, g_kernel_items[i].file.name);
  957.         g_kernel_items[i].menu_item = item;
  958.         if (g_kernel_items[i].has_rd)
  959.             SetItemIcon(menu, item, icons_ramdisk);
  960.         else if (g_kernel_items[i].kdesc.zImage)
  961.             SetItemIcon(menu, item, icons_gzipped);
  962.         else
  963.             SetItemIcon(menu, item, icons_normal_kernel);
  964.         item++;
  965.         lastDirID = g_kernel_items[i].file.spec.parID;
  966.         lastVol = g_kernel_items[i].file.spec.vRefNum;
  967.     }
  968.  
  969.     SetControlMinimum(g_kernel_menu, 1);
  970.     SetControlMaximum(g_kernel_menu, item);
  971.     SetControlValue(g_kernel_menu, 1);
  972. }
  973.  
  974. /* Entry point */
  975. pascal void
  976. main(void)
  977. {
  978.     GrafPtr            oldPort;
  979.     long            response;
  980.     static Str255    tempStr;
  981.     
  982.     /* Silently dies on sheepshaver */
  983.     if (((*(UInt32 *)0x2800)) == 'Baah') {
  984. #if BOOTX_BUILD_INIT
  985.         FragmentTerminate();
  986. #endif
  987.         return;
  988.     }
  989.     
  990.     g_my_zone = GetZone();
  991.     
  992. #if BOOTX_TRACE
  993. #if BOOTX_BUILD_INIT
  994.     ST_TraceInit("BootX INIT", 1, NULL);
  995. #else
  996.     ST_TraceInit("BootX App", 1, NULL);
  997. #endif
  998. #endif
  999.  
  1000.     check_opt_keys();
  1001.     setup_debug_context(g_debug_visible);
  1002.     show_context();
  1003.     
  1004.     dt_printf(dct, "Initing MacOS Toolbox...¥n");
  1005.     init_macos_toolbox();
  1006.  
  1007.     dt_printf(dct, "Initing BootX...¥n");
  1008.     g_dialog                = NULL;
  1009.     g_mount_queue.qHead        = NULL;
  1010.     g_mount_queue.qTail        = NULL;
  1011.     g_mount_queue.qFlags    = NULL;
  1012.     g_ramdisk                = NULL;
  1013.     g_L2CR_pref                = false;
  1014.     g_L2CR_set                = false;
  1015.     g_L2CR_value            = 0;
  1016.     g_L2CR_available        = false;
  1017.     g_entry_ticks            = TickCount();
  1018.     g_force_video_setup        = true;
  1019.     
  1020.     g_vm_present = false;
  1021.     if (Gestalt(gestaltVMAttr, &response) == noErr)
  1022.         if (response & (1 << gestaltVMPresent))
  1023.             g_vm_present = true;
  1024.     if (Gestalt(gestaltNativeCPUfamily, &response) == noErr)
  1025.     {
  1026.         if (response == gestaltCPU750)
  1027.             g_L2CR_available = true;
  1028.     } else if (Gestalt(gestaltNativeCPUtype, &response) == noErr)
  1029.         if (response == gestaltCPU750)
  1030.             g_L2CR_available = true;
  1031.  
  1032.  
  1033.     g_arch_PCI = false;
  1034.     if (Gestalt(gestaltOpenFirmwareInfo, &response) == noErr)
  1035.         if (Gestalt(gestaltNameRegistryVersion, &response) == noErr)
  1036.             g_arch_PCI = true;
  1037.     if (((long)RegistryEntryIDInit == kUnresolvedCFragSymbolAddress)||
  1038.         ((long)FlushProcessorCache == kUnresolvedCFragSymbolAddress))
  1039.             g_arch_PCI = false;
  1040.  
  1041. //    g_page_size = g_arch_PCI ? GetLogicalPageSize() : 4096;
  1042.  
  1043.  
  1044.     GetWMgrPort(&oldPort);
  1045.     SetPort(oldPort);
  1046.  
  1047.     // Setup default BootX options
  1048. //    GetIndString(g_kernel_args, string_kernel_args, 1);
  1049.     GetIndString(tempStr, string_boot_delay, 1);
  1050.     StringToNum(tempStr, (long *)&g_autoboot_delay);
  1051.     g_autoboot_delay    *= 60;
  1052.     g_current_choice    = boot_macos;
  1053.     g_video_of_only        = false;
  1054.         
  1055.     // Setup device tree options
  1056.     device_tree_skip_macos            = 1;        // Skip MacOS drivers
  1057.     device_tree_max_prop_length        = 1024;        // Max copied property length
  1058.  
  1059.     // Locate the kernel files
  1060.     dt_printf(dct, "Looking up valid kernels...¥n");
  1061.     lookup_kernels();
  1062.     dt_printf(dct, "Found %d kernels¥n", g_kernel_items_count);
  1063.     g_boot_choices[boot_linux][1] = (g_kernel_items_count != 0);
  1064.     
  1065.     // Locate the default (old way) ramdisk. Prefs can override this
  1066.     if (g_kernel_items_count)
  1067.         locate_ramdisk();
  1068.     g_use_ramdisk = g_have_ramdisk;
  1069.     
  1070. #if BOOTX_BUILD_INIT
  1071.     // Locate MkLinux booter
  1072.     g_boot_choices[boot_mklinux][1] = locate_mklinux();
  1073. #endif    
  1074.     
  1075.     dt_printf(dct, "VM present                 : %d¥n", g_vm_present);
  1076. //    dt_printf(dct, "Page size                  : %d¥n", g_page_size);
  1077.     dt_printf(dct, "Autoboot_delay             : %d¥n", g_autoboot_delay);
  1078.     dt_printf(dct, "L2CR available on this CPU : %d¥n", g_L2CR_available);
  1079.     dt_printf(dct, "PCI Arch                   : %d¥n", g_arch_PCI);
  1080.     if (g_have_ramdisk)
  1081.         dt_printf(dct, "default RAM-disk found¥n");
  1082.     if (g_boot_choices[boot_mklinux][1])
  1083.         dt_printf(dct, "MkLinux booter found¥n");
  1084.  
  1085.     if (!g_boot_choices[boot_linux][1] && !g_boot_choices[boot_mklinux][1]) {
  1086.         DEBUG_ERR(0, error_no_kernel);
  1087.         goto bail;
  1088.     }
  1089.         
  1090.     // Create main dialog box
  1091.     if (!create_dialog())
  1092.         goto bail;
  1093.  
  1094.     if (g_kernel_items_count)
  1095.         build_kernels_menu();
  1096.         
  1097.     // Load eventual prefs file
  1098.     load_prefs();
  1099.  
  1100.     // Display the dialog
  1101.     SelectDialogItemText(g_dialog, field_kernel_args, 0, 255);
  1102.     ShowWindow(g_dialog);
  1103.     DrawDialog(g_dialog);
  1104.  
  1105.     // Main event loop
  1106.     do_main_dialog();
  1107.         
  1108.     // Check user choice and boot
  1109.     if (g_current_choice == boot_linux) {
  1110.         boot_kernel_desc_t    *kernel_infos;
  1111.         boot_ramdisk_desc_t    *ramdisk_infos;
  1112.         boot_params_t        params;
  1113.         
  1114.         /* A little bit hacky ... */
  1115.         static char args[2048];
  1116.         
  1117.         params.args = args;
  1118.         fill_boot_options(&kernel_infos, &ramdisk_infos, ¶ms);
  1119.         if (kernel_infos) {
  1120.             dispose_dialog();
  1121.             SetZone(SystemZone());
  1122.             SetCursor(*GetCursor(watchCursor));
  1123.             dt_printf(dct, "Begin Linux boot...¥n");
  1124.             debug_checkpoint();
  1125.             do_boot(kernel_infos, ramdisk_infos, ¶ms);
  1126.         #if BOOTX_BUILD_INIT
  1127.             DebugStr("¥pShould not get here !");
  1128.         #endif
  1129.             SetZone(g_my_zone);
  1130.         }
  1131.     } else if (g_current_choice == boot_mklinux) {
  1132.             dt_printf(dct, "Begin MkLinux boot...¥n");
  1133.             SetZone(g_my_zone);
  1134.             dispose_dialog();
  1135.             do_boot_mklinux();
  1136.     }
  1137.  
  1138. bail:
  1139.     
  1140.     dt_printf(dct, "Exiting BootX !¥n");
  1141.     SetZone(g_my_zone);
  1142.     
  1143.     if (g_dialog)
  1144.         dispose_dialog();
  1145.  
  1146.     GetWMgrPort(&oldPort);
  1147.     SetPort(oldPort);
  1148.  
  1149. #if BOOTX_BUILD_INIT
  1150.     resend_mount_events();
  1151. #endif    
  1152.  
  1153. #if BOOTX_BUILD_INIT
  1154.     FragmentTerminate();
  1155. #endif
  1156. }
  1157.  
  1158. void
  1159. do_main_dialog(void)
  1160. {
  1161.     Boolean            finished;
  1162.     Boolean            counter_on;
  1163.     Boolean            stop_counter;
  1164.     Boolean            simulate;
  1165.     ModalFilterUPP    std_filter;
  1166.     UInt32            last_disp_ticks;
  1167.     DialogPtr        dialog;
  1168.     
  1169.     finished = false;
  1170.     simulate = false;
  1171.     stop_counter = false;
  1172. #if BOOTX_BUILD_INIT
  1173.     counter_on = true;
  1174. #else
  1175.     counter_on = false;
  1176. #endif
  1177.     
  1178.     last_disp_ticks = g_entry_ticks - 60;
  1179.  
  1180.     if (GetStdFilterProc(&std_filter) != noErr) {
  1181.         std_filter = NULL;
  1182.     }
  1183.     
  1184.     kernel_selection_changed();
  1185.     
  1186.     while(!finished) {
  1187.         EventRecord    event;
  1188.         short        itemHit;
  1189.         Boolean        handled;
  1190.         Boolean        hasEvent;
  1191.         short        curField;
  1192.         
  1193.         SetPort(g_dialog);
  1194.         hasEvent = WaitNextEvent(everyEvent, &event, 1, NULL);
  1195.         SetPort(g_dialog);
  1196.         SetZone(g_my_zone);
  1197.     
  1198.         itemHit = 0;
  1199.         handled = false;
  1200.         
  1201.         if (counter_on) {
  1202.             UInt32    now = TickCount();
  1203.             
  1204.             if ((now - g_entry_ticks) >= g_autoboot_delay) {
  1205.                 counter_on = false;
  1206.                 itemHit = g_boot_choices[g_current_choice][0];
  1207.                 simulate = true;
  1208.                 handled = true;
  1209.             }
  1210.             else if ((now - last_disp_ticks) >= 30) {
  1211.                 static char temp[256];
  1212.                 
  1213.                 sprintf(temp, "Boot in %d seconds   ", (int)((g_autoboot_delay - (now - g_entry_ticks)) / 60));
  1214.                 c2pstr(temp);
  1215.                 SetDialogItemText(g_status_item, (StringPtr)temp);
  1216.                 last_disp_ticks = now;
  1217.             }
  1218.         }
  1219.         
  1220.         if (!handled)
  1221.             handled = ((std_filter != NULL)
  1222.                 ? CallModalFilterProc(std_filter, g_dialog, &event, &itemHit)
  1223.                 : false);
  1224.  
  1225.         curField = ((DialogPeek)g_dialog)->editField+1;
  1226.         
  1227.         if (!handled && hasEvent) {
  1228.             UInt8 c;
  1229.             
  1230.             switch(event.what) {
  1231.                 case updateEvt:
  1232.                     if ((DialogPtr)event.message == g_dialog) {
  1233.                         handled = TRUE;
  1234.                         BeginUpdate(g_dialog);
  1235.                         RGBBackColor(&g_back_color);
  1236.                         DrawDialog(g_dialog);
  1237.                         setup_default_buttons();
  1238.                         EndUpdate(g_dialog);
  1239.                     } else {
  1240.                         BeginUpdate((WindowPtr)event.message);
  1241.                         EndUpdate((WindowPtr)event.message);
  1242.                     }
  1243.                     break;
  1244.                 
  1245.                 case keyDown:
  1246.                 case autoKey:
  1247.                     c = (event.message & charCodeMask);
  1248.                     if (event.modifiers & cmdKey) {
  1249.                         switch(c) {
  1250.                             case 'q':
  1251.                             case 'Q':
  1252.                                 itemHit = button_boot_macos;
  1253.                                 handled = true;
  1254.                                 break;
  1255.                             case 's':
  1256.                             case 'S':
  1257.                                 itemHit = button_set_default;
  1258.                                 handled = true;
  1259.                                 simulate = true;
  1260.                                 break;
  1261.                             case 'o':
  1262.                             case 'O':
  1263.                                 itemHit = button_options;
  1264.                                 handled = true;
  1265.                                 simulate = true;
  1266.                                 break;
  1267.                         }
  1268.                     } else {
  1269.                         switch(c) {
  1270.                             case 0x09:    // Tab
  1271.                                 do
  1272.                                     g_current_choice = (g_current_choice + 1) % boot_choice_count;
  1273.                                 while(!g_boot_choices[g_current_choice][1]);
  1274.                                 setup_default_buttons();
  1275.                                 handled = true;
  1276.                                 break;
  1277.                         }
  1278.                         if (!handled && (curField == field_ramd_size)) {
  1279.                             if ((c < '0') || (c > '9')) {
  1280. //                                dt_printf(dct, "key: 0x%x¥n", c);
  1281.                                 switch(c) { 
  1282.                                     case 8:
  1283.                                     case 0x1c:
  1284.                                     case 0x1d:
  1285.                                     case 0x1e:
  1286.                                     case 0x1f:
  1287.                                     case 0x7f:
  1288.                                         break;
  1289.                                     default:
  1290.                                         event.what = nullEvent;
  1291.                                 }
  1292.                             }
  1293.                         }
  1294.                     }
  1295.                     
  1296.                     // We stop the counter when a key is pressed    
  1297.                     stop_counter = true;        
  1298.                     break;
  1299.                 
  1300.                 case diskEvt:
  1301.                     dt_printf(dct, "Got mount event, msg: 0x%08lx¥n", event.message);
  1302. #if BOOTX_BUILD_INIT
  1303.                     save_mount_event(&event);
  1304. #else                    
  1305.                     if ((HiWord(event.message) != noErr)&&(HiWord(event.message) != volOnLinErr)) {
  1306.                         Point pt = {100, 100};
  1307.                         DIBadMount(pt, event.message);
  1308.                     }
  1309. #endif
  1310.                     break;
  1311.             }
  1312.         }
  1313.         
  1314.         // All non-filtered events are given to the default event proc.
  1315.         dialog = g_dialog;
  1316.         if (!handled && IsDialogEvent(&event)) {
  1317.             handled = DialogSelect(&event, &dialog, &itemHit);
  1318.         }
  1319.         if (handled) {
  1320.             if (dialog == g_dialog) {
  1321.                 int i;
  1322.                 
  1323.                 if (simulate) {
  1324.                     Rect    itemBox;
  1325.                     short    itemType;
  1326.                     Handle    itemHandle;
  1327.                     UInt32    toto;
  1328.                     
  1329.                     GetDialogItem (g_dialog, itemHit, &itemType, &itemHandle, &itemBox);
  1330.                     HiliteControl((ControlHandle)itemHandle, 1);
  1331.                     Delay(10, &toto);
  1332.                     HiliteControl((ControlHandle)itemHandle, 0);
  1333.                     simulate = false;
  1334.                 }
  1335.                 for(i=0; i<boot_choice_count; i++)
  1336.                     if (g_boot_choices[i][0] == itemHit) {
  1337.                         g_current_choice = i;
  1338.                         finished = true;
  1339.                         break;
  1340.                     }
  1341.  
  1342.                 switch(itemHit)
  1343.                 {
  1344.                     case button_set_default:
  1345.                         stop_counter = true;
  1346.                         save_prefs();
  1347.                         break;
  1348.  
  1349.                     case check_video_of_only:
  1350.                         stop_counter = true;
  1351.                         g_video_of_only = !g_video_of_only;
  1352.                         SetControlValue(g_video_of_only_cntl, g_video_of_only);
  1353.                         break;
  1354.  
  1355.                     case menu_kernels:
  1356.                         stop_counter = true;
  1357.                         kernel_selection_changed();
  1358.                         break;
  1359.                     
  1360.                     case button_options:
  1361.                         do_options_dialog();
  1362.                         kernel_selection_changed();
  1363.                         break;
  1364.                 }
  1365.             }
  1366.         }
  1367.         if (counter_on && stop_counter) {
  1368.             counter_on = FALSE;
  1369.             SetDialogItemText(g_status_item, "¥p");
  1370.         }
  1371.         if (g_use_ramdisk || g_current_kernel_has_rd) {
  1372.             ShowDialogItem(g_dialog, has_ramdisk_item);
  1373.             ShowDialogItem(g_dialog, ramd_label);
  1374.             ShowDialogItem(g_dialog, field_ramd_size);
  1375.             HideDialogItem(g_dialog, field_root_device);
  1376.             HideDialogItem(g_dialog, root_label_1);
  1377.             HideDialogItem(g_dialog, root_label_2);
  1378.         } else {
  1379.             HideDialogItem(g_dialog, has_ramdisk_item);
  1380.             HideDialogItem(g_dialog, ramd_label);
  1381.             HideDialogItem(g_dialog, field_ramd_size);
  1382.             ShowDialogItem(g_dialog, field_root_device);
  1383.             ShowDialogItem(g_dialog, root_label_1);
  1384.             ShowDialogItem(g_dialog, root_label_2);
  1385.         }
  1386.     }
  1387. }
  1388.  
  1389. Boolean
  1390. choose_ramdisk_file(boot_file_t* file, boot_ramdisk_desc_t* desc)
  1391. {
  1392.     StandardFileReply    reply;
  1393.  
  1394.     StandardGetFile(NULL, 0, NULL, &reply);
  1395.     if (!reply.sfGood)
  1396.         return false;
  1397.  
  1398.     file->spec = reply.sfFile;
  1399.     return check_ramdisk_file(file, desc);
  1400. }
  1401.  
  1402. void
  1403. do_options_dialog(void)
  1404. {
  1405.     Boolean            finished;
  1406.     ModalFilterUPP    std_filter;
  1407.     DialogPtr        dialog, dlg;
  1408.     ControlHandle    use_ramdisk_cntl;
  1409.     ControlHandle    set_L2CR_cntl;
  1410.     ControlHandle    choose_rd_cntl;
  1411.     ControlHandle    force_video_cntl;
  1412.     ControlHandle    force_scsi_cntl;
  1413.     Handle            rd_path_item;
  1414.     DialogPeek        dp;
  1415.     short            itemType;
  1416.     Rect            itemBox;
  1417. //    Handle            itemHandle;
  1418.     FontInfo        theFontInfo;
  1419.     Boolean                        has_rd_defined;
  1420.     Boolean                        use_rd;
  1421.     static boot_file_t            ramdisk_file;
  1422.     static boot_file_t            ramdisk_temp;
  1423.     static boot_ramdisk_desc_t    ramdisk_desc;
  1424.     static Str255                tempStr;
  1425.     
  1426.     dialog = GetNewDialog(dialog_options, NULL, (WindowPtr)-1);
  1427.     if (!dialog) {
  1428.         DEBUG_ERR(0, error_create_dialog);
  1429.         return;
  1430.     }
  1431.     SetPort(dialog);
  1432.     
  1433.     dp = (DialogPeek)dialog;
  1434.     TextFont((**(dp->textH)).txFont = 3);
  1435.     TextSize((**(dp->textH)).txSize = 9);
  1436.     TextFace((**(dp->textH)).txFace = 0);
  1437.     GetFontInfo(&theFontInfo);
  1438.     (**(dp->textH)).lineHeight = theFontInfo.ascent + theFontInfo.descent + theFontInfo.leading;
  1439.     (**(dp->textH)).fontAscent = theFontInfo.ascent;
  1440.  
  1441.     GetDialogItem(dialog, opt_check_use_ram_disk, &itemType, (Handle *)&use_ramdisk_cntl, &itemBox) ;
  1442.     GetDialogItem(dialog, opt_check_set_l2cr, &itemType, (Handle *)&set_L2CR_cntl, &itemBox);
  1443.     GetDialogItem(dialog, opt_button_choose_ramdisk, &itemType, (Handle *)&choose_rd_cntl, &itemBox);
  1444.     GetDialogItem(dialog, opt_text_ramdisk_path, &itemType, &rd_path_item, &itemBox);
  1445.     GetDialogItem(dialog, opt_check_force_video, &itemType, (Handle *)&force_video_cntl, &itemBox);
  1446.     GetDialogItem(dialog, opt_check_force_scsi_on, &itemType, (Handle *)&force_scsi_cntl, &itemBox);
  1447.     if (g_L2CR_available && g_L2CR_pref)
  1448.         SetControlValue(set_L2CR_cntl, g_L2CR_set);
  1449.     else
  1450.         HiliteControl(set_L2CR_cntl, 255);
  1451.     if (g_have_ramdisk) {
  1452.         short pathLen;
  1453.         Handle pathHandle;
  1454.  
  1455.         has_rd_defined = true;
  1456.         use_rd = g_use_ramdisk;
  1457.         memcpy(&ramdisk_file, &g_std_ramdisk_file, sizeof(ramdisk_file));
  1458.         memcpy(&ramdisk_desc, &g_std_ramdisk, sizeof(ramdisk_desc));
  1459.         ramdisk_desc.file = &ramdisk_file;
  1460.         SetControlValue(use_ramdisk_cntl, use_rd);
  1461.         if (FSpGetFullPath(&ramdisk_file.spec, &pathLen, &pathHandle) == noErr) {
  1462.             if (pathLen > 255)
  1463.                 pathLen = 255;
  1464.             BlockMoveData(*pathHandle, tempStr+1, pathLen);
  1465.             tempStr[0] = pathLen;
  1466.             SetDialogItemText(rd_path_item, tempStr);
  1467.             DisposeHandle(pathHandle);
  1468.         }
  1469.     } else {
  1470.         has_rd_defined = false;
  1471.         use_rd = false;
  1472.     }
  1473.     SetControlValue(force_video_cntl, g_force_video_setup);
  1474.     SetControlValue(force_scsi_cntl, g_force_scsi_on);
  1475.     SetControlValue(use_ramdisk_cntl, use_rd);
  1476.     HiliteControl(choose_rd_cntl, use_rd ? 0 : 255);
  1477.  
  1478.     SetDialogDefaultItem(dialog, opt_button_ok);
  1479.     SetDialogCancelItem(dialog, opt_button_cancel);
  1480.  
  1481.     ShowWindow(dialog);
  1482.     DrawDialog(dialog);
  1483.     
  1484.     finished = false;
  1485.     if (GetStdFilterProc(&std_filter) != noErr) {
  1486.         std_filter = NULL;
  1487.     }
  1488.     
  1489.     while(!finished) {
  1490.         EventRecord    event;
  1491.         short        itemHit;
  1492.         Boolean        handled;
  1493.         Boolean        hasEvent;
  1494.         
  1495.         SetPort(dialog);
  1496.         hasEvent = WaitNextEvent(everyEvent, &event, 1, NULL);
  1497.         SetPort(dialog);
  1498.         SetZone(g_my_zone);
  1499.     
  1500.         itemHit = 0;
  1501.         handled = false;
  1502.         
  1503.         handled = ((std_filter != NULL)
  1504.                 ? CallModalFilterProc(std_filter, dialog, &event, &itemHit)
  1505.                 : false);
  1506.  
  1507.         if (!handled && hasEvent) {
  1508.             switch(event.what) {
  1509.                 case updateEvt:
  1510.                     if ((DialogPtr)event.message == dialog) {
  1511.                         handled = TRUE;
  1512.                         BeginUpdate(dialog);
  1513.                         RGBBackColor(&g_back_color);
  1514.                         DrawDialog(dialog);
  1515.                         EndUpdate(dialog);
  1516.                     } else if ((DialogPtr)event.message == g_dialog) {
  1517.                         handled = TRUE;
  1518.                         SetPort(g_dialog);
  1519.                         BeginUpdate(g_dialog);
  1520.                         RGBBackColor(&g_back_color);
  1521.                         DrawDialog(g_dialog);
  1522.                         EndUpdate(g_dialog);
  1523.                         SetPort(dialog);
  1524.                     } else {
  1525.                         BeginUpdate((WindowPtr)event.message);
  1526.                         EndUpdate((WindowPtr)event.message);
  1527.                     }
  1528.                     break;
  1529.                 
  1530.                 case diskEvt:
  1531.                     dt_printf(dct, "Got mount event, msg: 0x%08lx¥n", event.message);
  1532. #if BOOTX_BUILD_INIT
  1533.                     save_mount_event(&event);
  1534. #else                    
  1535.                     if ((HiWord(event.message) != noErr)&&(HiWord(event.message) != volOnLinErr)) {
  1536.                         Point pt = {100, 100};
  1537.                         DIBadMount(pt, event.message);
  1538.                     }
  1539. #endif
  1540.                     break;
  1541.             }
  1542.         }
  1543.         
  1544.         // All non-filtered events are given to the default event proc.
  1545.         dlg = dialog;
  1546.         if (!handled && IsDialogEvent(&event)) {
  1547.             handled = DialogSelect(&event, &dlg, &itemHit);
  1548.         }
  1549.         
  1550.         if (handled) {
  1551.             if (dlg == dialog) {
  1552.                 switch(itemHit) {
  1553.                     case opt_check_use_ram_disk:
  1554.                         use_rd = !GetControlValue(use_ramdisk_cntl);
  1555.                         SetControlValue(use_ramdisk_cntl, use_rd);
  1556.                         HiliteControl(choose_rd_cntl, use_rd ? 0 : 255);
  1557.                         if (has_rd_defined)
  1558.                             break;
  1559.                     case opt_button_choose_ramdisk:
  1560.                         memcpy(&ramdisk_temp, &ramdisk_file, sizeof(ramdisk_temp));
  1561.                         if (choose_ramdisk_file(&ramdisk_temp, &ramdisk_desc)) {
  1562.                             short pathLen;
  1563.                             Handle pathHandle;
  1564.                             memcpy(&ramdisk_file, &ramdisk_temp, sizeof(ramdisk_file));
  1565.                             if (FSpGetFullPath(&ramdisk_file.spec, &pathLen, &pathHandle) == noErr) {
  1566.                                 if (pathLen > 255)
  1567.                                     pathLen = 255;
  1568.                                 BlockMoveData(*pathHandle, tempStr+1, pathLen);
  1569.                                 tempStr[0] = pathLen;
  1570.                                 SetDialogItemText(rd_path_item, tempStr);
  1571.                                 DisposeHandle(pathHandle);
  1572.                                 has_rd_defined = true;
  1573.                             }                            
  1574.                         }
  1575.                         if (!has_rd_defined) {
  1576.                             SetControlValue(use_ramdisk_cntl, use_rd = false);
  1577.                             HiliteControl(choose_rd_cntl, 255);
  1578.                         }
  1579.                         break;
  1580.                         
  1581.                     case opt_check_set_l2cr:
  1582.                         if (g_L2CR_available && g_L2CR_pref)
  1583.                             SetControlValue(set_L2CR_cntl, !GetControlValue(set_L2CR_cntl));
  1584.                         break;
  1585.                     
  1586.                     case opt_check_force_video:
  1587.                         SetControlValue(force_video_cntl, !GetControlValue(force_video_cntl));
  1588.                         break;
  1589.                     
  1590.                     case opt_check_force_scsi_on:
  1591.                         SetControlValue(force_scsi_cntl, !GetControlValue(force_scsi_cntl));
  1592.                         break;
  1593.  
  1594.                     case opt_button_ok:
  1595.                         g_use_ramdisk = use_rd;
  1596.                         g_have_ramdisk = has_rd_defined;
  1597.                         memcpy(&g_std_ramdisk_file, &ramdisk_file, sizeof(ramdisk_file));
  1598.                         memcpy(&g_std_ramdisk, &ramdisk_desc, sizeof(ramdisk_desc));
  1599.                         g_L2CR_set = GetControlValue(set_L2CR_cntl);
  1600.                         g_force_video_setup = GetControlValue(force_video_cntl);
  1601.                         g_force_scsi_on = GetControlValue(force_scsi_cntl);
  1602.                         finished = true;
  1603.                         break;
  1604.                     
  1605.                     case opt_button_cancel:
  1606.                         finished = true;
  1607.                         break;
  1608.  
  1609.                 }
  1610.             }
  1611.         }
  1612.     }
  1613.     
  1614.     DisposeDialog(dialog);
  1615.     SetPort(g_dialog);
  1616. }
  1617.  
  1618. void
  1619. kernel_selection_changed()
  1620. {
  1621.     UInt32    choice;
  1622.     UInt32    i;
  1623.     
  1624.     // Get selected kernel
  1625.     choice = 0;
  1626.     g_current_kernel_has_rd = false;
  1627.     for (i=0; i<g_kernel_items_count; i++) {
  1628.         if (g_kernel_items[i].menu_item == GetControlValue(g_kernel_menu)) {
  1629.             choice = i;
  1630.             g_current_kernel_has_rd = g_kernel_items[i].has_rd;
  1631.             return;
  1632.         }
  1633.     }
  1634. }
  1635.  
  1636. void
  1637. display_error(OSErr err, int msg, char *file, int line)
  1638. {
  1639.     static Str32    errStr;
  1640.     static Str32    lineStr;
  1641.     static Str255    fileStr;
  1642.     static Str255    msgStr;
  1643.     
  1644.     strcpy((char *)fileStr, file);
  1645.     c2pstr((char *)fileStr);
  1646.     GetIndString(msgStr, string_error_codes, msg);
  1647.     NumToString(err, errStr);
  1648.     NumToString(line, lineStr);
  1649.     
  1650.     ParamText(msgStr, errStr, fileStr, lineStr);
  1651.     Alert(alert_error, NULL);
  1652. }
  1653.  
  1654. void
  1655. load_prefs(void)
  1656. {
  1657.     FSSpec                prefFileSpec;
  1658.     short                prefFileRef;
  1659.     short                saveResFile;
  1660.     bootx_prefs_handle    prefs;
  1661.     OSErr                err;
  1662.     short                itemType;
  1663.     Rect                itemBox;
  1664.     Handle                itemHandle;
  1665.     Handle                rsrc;
  1666.     
  1667.     err = locate_file(string_prefs_file_names, kPreferencesFolderType, &prefFileSpec);
  1668.     if (err != noErr)
  1669.         return;
  1670.     
  1671.     saveResFile = CurResFile();
  1672.     
  1673.     prefFileRef = FSpOpenResFile(&prefFileSpec, fsRdPerm);
  1674.     if (prefFileRef == -1)
  1675.         return;
  1676.     
  1677.     UseResFile(prefFileRef);
  1678.     
  1679.     rsrc = Get1Resource('L2CR', 0);
  1680.     if (rsrc) {
  1681.         if (GetHandleSize(rsrc) == 4) {
  1682.             g_L2CR_pref        = true;
  1683.             g_L2CR_value    = *((UInt32 *)(*rsrc));
  1684.         }
  1685.         ReleaseResource(rsrc);
  1686.     }
  1687.     
  1688.     prefs = (bootx_prefs_handle)Get1Resource('PREF', 128);
  1689.     if (prefs == NULL)
  1690.         goto bail_close;
  1691.     
  1692.     // Compare oldest compatible of prefs with version compiled with this code
  1693.     if ((**prefs).compatible_version > BOOTX_PREFS_VERSION)
  1694.         goto bail_release;
  1695.     
  1696.     HLock((Handle)prefs);
  1697.     
  1698.     g_current_choice    = (**prefs).boot_choice;
  1699.     g_use_ramdisk        = (**prefs).use_ramdisk;
  1700.     g_video_of_only        = (**prefs).video_of_only;
  1701.     g_L2CR_set            = (**prefs).use_l2cr_settings && g_L2CR_pref;
  1702.     
  1703.     if (!g_boot_choices[g_current_choice][1])
  1704.         g_current_choice = boot_macos;
  1705.         
  1706.     GetDialogItem(g_dialog, field_kernel_args, &itemType, &itemHandle, &itemBox);
  1707.     if (itemHandle)
  1708.         SetDialogItemText(itemHandle, (**prefs).command_line);
  1709.  
  1710.     if ((**prefs).version >= 2) {
  1711.         GetDialogItem(g_dialog, field_root_device, &itemType, &itemHandle, &itemBox);
  1712.         if (itemHandle)
  1713.             SetDialogItemText(itemHandle, (**prefs).root_device);
  1714.     }
  1715.  
  1716.     if ((**prefs).version >= 4) {
  1717.         int i;
  1718.         
  1719.         for (i=0;i<g_kernel_items_count; i++)
  1720.             if (EqualString(g_kernel_items[i].file.name, (**prefs).kernel_name, false, false)) {
  1721.                 SetControlValue(g_kernel_menu, g_kernel_items[i].menu_item);
  1722.             }
  1723.     }
  1724.  
  1725.     if ((**prefs).version >= 5) {
  1726.         Str32 tempStr;
  1727.         g_force_video_setup = (**prefs).force_video_setup;
  1728.         g_force_scsi_on = (**prefs).force_scsi_on;
  1729.         if ((**prefs).ramdisk_path[0] != 0) {
  1730.             OSErr err;
  1731.             FSSpec spec;
  1732.             err = FSpLocationFromFullPath(
  1733.                         strlen((**prefs).ramdisk_path),
  1734.                         (**prefs).ramdisk_path,
  1735.                         &spec);
  1736.             if (err == noErr) {
  1737.                 g_std_ramdisk_file.spec = spec;
  1738.                 g_std_ramdisk_file.rn    = -1;
  1739.                 g_std_ramdisk_file.size    = 0;
  1740.                 g_std_ramdisk_file.name    = g_std_ramdisk_file.spec.name;
  1741.         
  1742.                 g_have_ramdisk = check_ramdisk_file( &g_std_ramdisk_file,
  1743.                                                      &g_std_ramdisk);
  1744.             }
  1745.         }
  1746.         NumToString(8192, tempStr);
  1747.         SetDialogItemText(ramd_size_field, tempStr);
  1748.     }
  1749.     
  1750.     SetControlValue(g_video_of_only_cntl, g_video_of_only);
  1751.     
  1752.     setup_default_buttons();
  1753.  
  1754. bail_release:
  1755.     HUnlock((Handle)prefs);
  1756.     ReleaseResource((Handle)prefs);
  1757. bail_close:
  1758.     CloseResFile(prefFileRef);
  1759.     
  1760.     UseResFile(saveResFile);
  1761. }
  1762.  
  1763. void
  1764. save_prefs(void)
  1765. {
  1766.     short                prefsVRefNum;
  1767.     long                prefsParID;
  1768.     static Str255        fileName;
  1769.     FSSpec                prefFileSpec;
  1770.     short                prefFileRef;
  1771.     short                saveResFile;
  1772.     bootx_prefs_handle    prefs;
  1773.     OSErr                err;
  1774.     short                itemType;
  1775.     Rect                itemBox;
  1776.     Handle                itemHandle;
  1777.     int                    i;
  1778.     Str32                tempStr;
  1779.     UInt32                tempLong;
  1780.     
  1781.     // Build kernel FSSpec
  1782.     err = FindFolder(    kOnSystemDisk,
  1783.                         kPreferencesFolderType,
  1784.                         true,
  1785.                         &prefsVRefNum,
  1786.                         &prefsParID);
  1787.     if (err != noErr) {
  1788.         DEBUG_ERR(err, error_access_prefs);
  1789.         return;
  1790.     }
  1791.     GetIndString(fileName, string_prefs_file_names, 1);
  1792.     
  1793.     saveResFile = CurResFile();
  1794.  
  1795.     err = FSMakeFSSpec(    prefsVRefNum, prefsParID, fileName, &prefFileSpec);
  1796.     if (err == fnfErr) {
  1797.         FSpCreateResFile(&prefFileSpec, 'BooX', 'pref', smSystemScript);
  1798.         err = ResError();
  1799.     }
  1800.     if (err != noErr) {
  1801.         DEBUG_ERR(err, error_loadcreate_prefs);
  1802.         return;
  1803.     }
  1804.     
  1805.     prefFileRef = FSpOpenResFile(&prefFileSpec, fsWrPerm);
  1806.     if (prefFileRef == -1) {
  1807.         err = ResError();
  1808.         DEBUG_ERR(err, error_openwrite_prefs);
  1809.         return;
  1810.     }
  1811.     
  1812.     prefs = (bootx_prefs_handle)Get1Resource('PREF', 128);
  1813.     if (prefs == NULL) {
  1814.         prefs = (bootx_prefs_handle)NewHandle(sizeof(bootx_prefs));
  1815.         if (prefs == NULL) {
  1816.             err = MemError();
  1817.             DEBUG_ERR(err, error_alloc_prefs);
  1818.             goto bail_close;
  1819.         }
  1820.         AddResource((Handle)prefs, 'PREF', 128, "¥p");
  1821.         err = ResError();
  1822.         if (err != noErr)
  1823.         if (prefs == NULL)
  1824.         {
  1825.             DisposeHandle((Handle)prefs);
  1826.             DEBUG_ERR(err, error_add_prefs);
  1827.             goto bail_close;
  1828.         }
  1829.     } else
  1830.         SetHandleSize((Handle)prefs, sizeof(bootx_prefs));
  1831.  
  1832.     HLock((Handle)prefs);
  1833.     
  1834.     memset(*prefs, 0, sizeof(bootx_prefs));
  1835.     (**prefs).version                = BOOTX_PREFS_VERSION;
  1836.     (**prefs).compatible_version    = BOOTX_PREFS_COMPATIBLE_VERSION;
  1837.     (**prefs).boot_choice            = g_current_choice;
  1838.     (**prefs).use_ramdisk            = g_use_ramdisk;
  1839.     (**prefs).video_of_only            = g_video_of_only;
  1840.     (**prefs).use_l2cr_settings        = g_L2CR_set;
  1841.     (**prefs).ramdisk_path[0]        = 0;
  1842.     (**prefs).force_video_setup        = g_force_video_setup;
  1843.     (**prefs).force_scsi_on            = g_force_scsi_on;
  1844.     
  1845.     GetDialogItem(g_dialog, field_kernel_args, &itemType, &itemHandle, &itemBox);
  1846.     if (itemHandle)
  1847.         GetDialogItemText(itemHandle, (**prefs).command_line);
  1848.     GetDialogItem(g_dialog, field_root_device, &itemType, &itemHandle, &itemBox);
  1849.     if (itemHandle)
  1850.         GetDialogItemText(itemHandle, (**prefs).root_device);
  1851.     
  1852.     for (i=0; i<g_kernel_items_count; i++)
  1853.     if (g_kernel_items[i].menu_item == GetControlValue(g_kernel_menu))
  1854.         pstrcpy((**prefs).kernel_name, g_kernel_items[i].file.name);
  1855.  
  1856.     if (g_have_ramdisk) {
  1857.         short pathLen;
  1858.         Handle pathHandle;
  1859.         err = FSpGetFullPath(&g_std_ramdisk_file.spec, &pathLen, &pathHandle);
  1860.         if (err == noErr && pathHandle) {
  1861.             if (pathLen > 1023)
  1862.                 pathLen = 1023;
  1863.             BlockMoveData(*pathHandle, (**prefs).ramdisk_path, pathLen);
  1864.             (**prefs).ramdisk_path[pathLen] = 0;
  1865.             DisposeHandle(pathHandle);
  1866.         }
  1867.     }
  1868.     GetDialogItemText(ramd_size_field, tempStr);
  1869.     StringToNum(tempStr, (long *)&tempLong);
  1870.     (**prefs).ramdisk_size = tempLong;
  1871.     
  1872.     HUnlock((Handle)prefs);
  1873.     ChangedResource((Handle)prefs);
  1874.     WriteResource((Handle)prefs);
  1875.     ReleaseResource((Handle)prefs);
  1876.     
  1877. bail_close:
  1878.     CloseResFile(prefFileRef);
  1879.     UseResFile(saveResFile);
  1880.     FlushVol(NULL, prefsVRefNum);
  1881. }
  1882.  
  1883.  
  1884. void
  1885. do_boot_mklinux(void)
  1886. {
  1887.     Handle     rsrc, patch;
  1888.     Str255    fileName;
  1889.     OSErr    err;
  1890.     FSSpec    prefFileSpec;
  1891.     short    prefFileRef, booterFileRef;
  1892.     short    prefsVRefNum;
  1893.     long    prefsParID;
  1894.     long    count;
  1895.         
  1896.     // Build fake MkLinux prefs file
  1897.     rsrc = Get1Resource('TEXT', text_mkboot_fake_prefs);
  1898.     if (rsrc == NULL)
  1899.     {
  1900.         DEBUG_ERR(ResError(), error_load_mk_text);
  1901.         return;
  1902.     }
  1903.     HNoPurge(rsrc);
  1904.     patch = Get1Resource('STR#', string_mkboot_patch);
  1905.     if (patch == NULL)
  1906.     {
  1907.         DEBUG_ERR(ResError(), error_load_mk_str);
  1908.         return;
  1909.     }
  1910.     HNoPurge(patch);
  1911.     DetachResource(patch);
  1912.     err = FindFolder(    kOnSystemDisk,
  1913.                         kPreferencesFolderType,
  1914.                         true,
  1915.                         &prefsVRefNum,
  1916.                         &prefsParID);
  1917.     if (err != noErr)
  1918.     {
  1919.         DEBUG_ERR(err, error_locate_mk_prefs);
  1920.         return;
  1921.     }
  1922.     GetIndString(fileName, string_mkboot_patch, 1);
  1923.     err = FSMakeFSSpec(prefsVRefNum, prefsParID, fileName, &prefFileSpec);
  1924.     if (err == fnfErr)
  1925.         err = FSpCreate(&prefFileSpec, 'ttxt', 'TEXT', smSystemScript);
  1926.     if (err != noErr)
  1927.     {
  1928.         DEBUG_ERR(err, error_open_mk_prefs);
  1929.         return;
  1930.     }
  1931.     err = FSpOpenDF(&prefFileSpec, fsWrPerm, &prefFileRef);
  1932.     if (err != noErr)
  1933.     {
  1934.         DEBUG_ERR(err, error_open_mk_prefs);
  1935.         return;
  1936.     }
  1937.     err = SetEOF(prefFileRef, count = GetHandleSize(rsrc));
  1938.     if (err != noErr)
  1939.     {
  1940.         DEBUG_ERR(err, error_write_mk_prefs);
  1941.         return;
  1942.     }
  1943.     HLock(rsrc);
  1944.     FSWrite(prefFileRef, &count, *rsrc);
  1945.     FSClose(prefFileRef);
  1946.     ReleaseResource(rsrc);
  1947.     
  1948.     // Open the booter
  1949.     booterFileRef = FSpOpenResFile(&g_mkboot_spec, fsRdPerm);
  1950.     if (booterFileRef == -1)
  1951.     {
  1952.         DEBUG_ERR(ResError(), error_open_mk_booter);
  1953.         return;
  1954.     }
  1955.     
  1956.     rsrc = Get1Resource('STR#', string_mkboot_patched);
  1957.     if (rsrc == NULL)
  1958.     {
  1959.         DEBUG_ERR(ResError(), error_bad_mk_booter);
  1960.         return;
  1961.     }
  1962.     HNoPurge(rsrc);
  1963.     SetHandleSize(rsrc, GetHandleSize(patch));
  1964.     BlockMoveData(*patch, *rsrc, GetHandleSize(patch));
  1965.  
  1966.     rsrc = Get1Resource('INIT', 0);
  1967.     HNoPurge(rsrc);
  1968.     HLock(rsrc);
  1969.     
  1970.     UseResFile(booterFileRef);
  1971.     CallUniversalProc((UniversalProcPtr)*rsrc, kPascalStackBased);    
  1972. }
  1973.  
  1974. Boolean
  1975. locate_mklinux(void)
  1976. {
  1977.     OSErr    err;
  1978.     
  1979.     // Lookup booter
  1980.     err = locate_file(string_mkboot_names, kSystemFolderType, &g_mkboot_spec);
  1981.     if (err == noErr)
  1982.         return true;
  1983.  
  1984.     err = locate_file(string_mkboot_names, kExtensionFolderType, &g_mkboot_spec);
  1985.     if (err == noErr)
  1986.         return true;
  1987.     
  1988.     return false;
  1989. }
  1990.  
  1991. static check_one_key(KeyMap map, UInt8 key_code)
  1992. {
  1993.     return ((((UInt8 *)map)[key_code >> 3] >> (key_code & 7)) & 1);
  1994. }
  1995.  
  1996. void
  1997. check_opt_keys(void)
  1998. {
  1999.     KeyMap    keys;
  2000.     
  2001.     GetKeys(keys);
  2002.     if (check_one_key(keys, 0x3a))
  2003.         g_debug_visible = 1;
  2004. }
  2005.  
  2006. void
  2007. debug_checkpoint(void)
  2008. {
  2009.     KeyMap    keys;
  2010.     
  2011.     do {
  2012.         GetKeys(keys);
  2013.         if (!check_one_key(keys, 0x3a))
  2014.             break;
  2015.     } while(true);
  2016. }
  2017.  
  2018. void
  2019. show_context(void)
  2020. {
  2021.     dt_printf(dct, "SystemZone start : 0x%08lx¥n", LMGetSysZone()->bkLim);
  2022.     dt_printf(dct, "SystemZone free  : 0x%08lx¥n", LMGetSysZone()->zcbFree);
  2023.     dt_printf(dct, "CurrenZone start : 0x%08lx¥n", LMGetTheZone()->bkLim);
  2024.     dt_printf(dct, "CurrenZone free  : 0x%08lx¥n", LMGetTheZone()->zcbFree);
  2025.     dt_printf(dct, "ApplZone start   : 0x%08lx¥n", LMGetApplZone()->bkLim);
  2026.     dt_printf(dct, "ApplZone free    : 0x%08lx¥n", LMGetApplZone()->zcbFree);
  2027.     dt_printf(dct, "ApplLimit        : 0x%08lx¥n", LMGetApplLimit());
  2028.     dt_printf(dct, "CurStackBase     : 0x%08lx¥n", LMGetCurStackBase());
  2029.     dt_printf(dct, "BufPtr           : 0x%08lx¥n", LMGetBufPtr());
  2030.     dt_printf(dct, "MemTop           : 0x%08lx¥n", LMGetMemTop());
  2031.     dt_printf(dct, "-> limit         : 0x%08lx¥n", ((UInt32)LMGetMemTop()/2 + 1024));
  2032. }
  2033.  
  2034. void
  2035. setup_debug_context(Boolean debug_visible)
  2036. {
  2037.     GDHandle    hdl;
  2038.     PixMapPtr    pm;
  2039.     
  2040.     dct = &g_dct;
  2041.     memset(dct, 0, sizeof(*dct));
  2042.     
  2043.     hdl = LMGetMainDevice();
  2044.     if (hdl == NULL || (**hdl).gdPMap == NULL)
  2045.         return;
  2046.     pm = *(**hdl).gdPMap;
  2047.     if (pm->baseAddr == NULL)
  2048.         return;
  2049.     
  2050.     dct->base = (unsigned char *)pm->baseAddr;
  2051.     dct->row_bytes = pm->rowBytes & 0x3fff;
  2052.     dct->width = pm->bounds.right - pm->bounds.left;
  2053.     dct->height = pm->bounds.bottom - pm->bounds.top;
  2054.     dct->depth = pm->pixelSize;
  2055.     dct->visible = debug_visible;
  2056.     
  2057.     if (dct->depth == 15)
  2058.         dct->depth = 16;
  2059.     
  2060.     dct->base += pm->bounds.top * dct->row_bytes;
  2061.     dct->base += pm->bounds.left * (dct->depth >> 3);
  2062.     
  2063.     dt_init(dct);
  2064. }
  2065.  
  2066.